/*
 * ORACLE PROPRIETARY/CONFIDENTIAL. Use is subject to license terms.
 *
 *
 *
 *
 *
 *
 *
 *
 *
 *
 *
 *
 *
 *
 *
 *
 *
 *
 *
 *
 */

/*
 *
 *
 *
 *
 *
 * Written by Doug Lea with assistance from members of JCP JSR-166
 * Expert Group and released to the public domain, as explained at
 * http://creativecommons.org/publicdomain/zero/1.0/
 */

package java.util.concurrent;
import java.util.Collection;
import java.util.concurrent.locks.AbstractQueuedSynchronizer;

/**
 * Semaphore 类实现了信号量机制，可用来控制同时访问特定资源的线程数量。
 * 它提供了获取和释放许可的方法，从而可以用于同步和线程同步。
 * 实现了 Serializable 接口，因此 Semaphore 对象可以进行序列化。
 */
public class Semaphore implements java.io.Serializable {
    private static final long serialVersionUID = -3222578661600680210L;


    private final Sync sync;


    abstract static class Sync extends AbstractQueuedSynchronizer {
        private static final long serialVersionUID = 1192457210091910933L;

        Sync(int permits) {
            setState(permits);
        }

        final int getPermits() {
            return getState();
        }

        /**
         * 尝试以非公平模式获取同步状态。此方法循环尝试减去获取的数量，
         * 如果结果小于0或者成功地设置了新的状态值，则返回剩余值。
         */
        final int nonfairTryAcquireShared(int acquires) {
            for (; ; ) {
                int available = getState();
                int remaining = available - acquires;
                if (remaining < 0 ||
                        compareAndSetState(available, remaining))
                    return remaining;
            }
        }

        /**
         * 尝试释放共享模式下的同步器。
         * 此方法的主要目的是在多线程环境下安全地释放共享资源。
         * 它通过CAS操作（compareAndSetState）来保证操作的原子性和线程安全性。
         * 如果释放后的许可数量小于当前许可数量，表示发生了溢出，抛出错误。
         */
        protected final boolean tryReleaseShared(int releases) {
            for (;;) {
                int current = getState();
                int next = current + releases;
                if (next < current) // overflow
                    throw new Error("Maximum permit count exceeded");
                if (compareAndSetState(current, next))
                    return true;
            }
        }

        /**
         * 减少指定数量的许可证
         *
         * @param reductions 要减少的许可证数量，必须是非负的
         */
        final void reducePermits(int reductions) {
            for (;;) {
                int current = getState();
                int next = current - reductions;
                if (next > current) // underflow
                    throw new Error("Permit count underflow");
                if (compareAndSetState(current, next))
                    return;
            }
        }

        /**
         * 从同步器中获取所有的许可，使得同步器的状态变为0
         * 这个方法被设计为一个最终方法，意味着它不能被子类覆盖
         * @return 返回之前同步器的状状态
         */
        final int drainPermits() {
            for (;;) {
                int current = getState();
                if (current == 0 || compareAndSetState(current, 0))
                    return current;
            }
        }
    }

    /**
     * 非公平锁模式
     */
    static final class NonfairSync extends Sync {
        private static final long serialVersionUID = -2694183684443567898L;

        NonfairSync(int permits) {
            super(permits);
        }

        /**
         * 尝试以共享模式获取,该方法应该查询对象的状态是否允许在共享模式下获取该对象，如果是这样，就可以获取它。
         * 该方法总是由执行获取的线程调用。 如果此方法报告失败，则获取方法可能将线程排队（如果尚未排队），直到被其他线程释放为止。
         */
        protected int tryAcquireShared(int acquires) {
            return nonfairTryAcquireShared(acquires);
        }
    }

    /**
     * 公平锁模式
     */
    static final class FairSync extends Sync {
        private static final long serialVersionUID = 2014338818796000944L;

        FairSync(int permits) {
            super(permits);
        }

        /**
         * 尝试以共享模式获取,该方法应该查询对象的状态是否允许在共享模式下获取该对象，如果是这样，就可以获取它。
         * 该方法总是由执行获取的线程调用。 如果此方法报告失败，则获取方法可能将线程排队（如果尚未排队），直到被其他线程释放为止。
         */
        protected int tryAcquireShared(int acquires) {
            for (;;) {
                if (hasQueuedPredecessors())
                    return -1;
                int available = getState();
                int remaining = available - acquires;
                if (remaining < 0 ||
                    compareAndSetState(available, remaining))
                    return remaining;
            }
        }
    }


    //  构造函数
    /*
     * 创建一个 Semaphore与给定数量的许可证和非公平公平设置。
     * @param permits permits的初始许可证。 该值可能为负数，在这种情况下，必须在任何获取被授予之前发布释放。
     */
    public Semaphore(int permits) {
        sync = new NonfairSync(permits);
    }

    /*
     * 创建一个 Semaphore与给定数量的许可证和给定的公平设置。
     * @param permits permits的初始许可证。 该值可能为负数，在这种情况下，必须在任何获取被授予之前发布释放。
     * @param fair {@code true} true如果这个信号量将保证首先在竞争中首先授予许可证，否则 false
     */
    public Semaphore(int permits, boolean fair) {
        sync = fair ? new FairSync(permits) : new NonfairSync(permits);
    }




    /*
     * 从此信号量获取许可证，阻止直到可用，否则线程为interrupted 。
     * 获得许可证，如果有可用并立即返回，则将可用许可证数量减少一个。
     * 如果没有可用的许可证，那么当前线程将被禁用以进行线程调度，并且处于休眠状态，直至发生两件事情之一：
     *   1、一些其他线程调用此信号量的release()方法，当前线程旁边将分配一个许可证; 要么
     *   2、一些其他线程interrupts当前线程。
     *  如果当前线程：
     *    1、在进入该方法时设置了中断状态; 要么
     *    2、是interrupted等候许可证，
     * 然后InterruptedException被关上，当前线程的中断状态被清除。
     * @throws InterruptedException  当前线程是否中断
     */
    public void acquire() throws InterruptedException {
        sync.acquireSharedInterruptibly(1);
    }

    /*
     * 从这个信号灯获取许可证，阻止一个可用的。
     * 获得许可证，如果有可用并立即返回，则将可用许可证数量减少一个。
     * 1、 如果没有许可证可用，那么当前线程将被禁用以进行线程调度，并且处于休眠状态，
     * 直到某个其他线程调用此信号量的release()方法，并且当前线程将被分配一个许可证。
     * 2、 如果当前线程是interrupted等待许可证，那么它将继续等待，但线程被分配许可证的时间可能会比接收到许可证的时间更改，
     * 而不会发生中断。 当该线程从该方法返回时，其中断状态将被设置。
     */
    public void acquireUninterruptibly() {
        sync.acquireShared(1);
    }

    /**
     * 从这个信号量获得许可证，只有在调用时可以使用该许可证。
     * 获得许可证，如果有可用并立即返回，值为true ，将可用许可证数量减少一个。
     * 如果没有许可证可用，那么该方法将立即返回值为false 。
     * 即使这个信号量被设置为使用一个合理的订购策略，
     * 如果一个可用的话，那么呼叫tryAcquire() 将立即获得许可，无论其他线程是否正在等待。 这种“趸船”行为在某些情况下是有用的，尽管它打破了公平。
     * 如果要尊重公平性，请使用tryAcquire(0, TimeUnit.SECONDS) ，几乎相当于（也检测到中断）。
     * @return {@code true} true如果获得许可证， false false
     */
    public boolean tryAcquire() {
        return sync.nonfairTryAcquireShared(1) >= 0;
    }

    /**
     * 如果在给定的等待时间内可用，并且当前线程尚未到达 interrupted，则从该信号量获取许可。
     * 获得许可证，如果可用并立即返回，值为true ，将可用许可证数量减少一个。
     * 如果没有许可证可用，那么当前的线程将被禁用以进行线程调度，并且处于休眠状态，直至发生三件事情之一：
     *    1、一些其他线程调用此信号量的release()方法，当前线程旁边将分配一个许可证;
     *    2、其他一些线程当前线程为interrupts
     *    3、指定的等待时间过去了。
     * 如果获得许可证，则返回值true 。
     * 如果当前线程：
     *    1、在进入该方法时设置了中断状态; 要么
     *    2、是interrupted等待获得许可证，
     * 然后InterruptedException被关上，当前线程的中断状态被清除。
     * 如果指定的等待时间过去，则返回值false 。 如果时间小于或等于零，该方法根本不会等待。
     * @param timeout 等待许可证的最长时间
     * @param unit    时间单位
     * @return {@code true} true如获得许可证，如果获得许可证之前经过的等待时间为 false
     * @throws InterruptedException 当前线程是否中断
     */
    public boolean tryAcquire(long timeout, TimeUnit unit)
            throws InterruptedException {
        return sync.tryAcquireSharedNanos(1, unit.toNanos(timeout));
    }

    /**
     * 释放许可证，将其返回到信号量。
     * 发放许可证，将可用许可证的数量增加一个。
     * 如果任何线程尝试获取许可证，那么选择一个被授予刚被释放的许可证。 （重新）线程调度用于线程调度。
     * 没有要求发布许可证的线程必须通过调用acquire()获取该许可证。 信号量的正确使用通过应用程序中的编程惯例来确定。
     */
    public void release() {
        sync.releaseShared(1);
    }

    /**
     * 从该信号量获取给定数量的许可证，阻止直到所有可用，否则线程为interrupted 。
     * 获得一定数量的许可证，如果可用，并立即返回，将可用许可证数量减少给定数量。
     * 如果没有足够的许可证可用，那么当前线程将被禁用以进行线程调度，并且处于休眠状态，直到发生两件事情之一：
     *   1、一些其他线程调用此信号量的一个release方法，当前线程旁边将分配许可证，并且可用许可证的数量满足此请求; 要么
     *   2、一些其他线程interrupts当前线程。
     *  如果当前线程：
     *   1、在进入该方法时设置了中断状态; 要么
     *   2、是interrupted等待许可证，
     * 然后InterruptedException被关上，当前线程的中断状态被清除。 将分配给此线程的任何许可证分配给尝试获取许可证的其他线程，如同通过拨打release()可用的许可证一样 。
     * @param permits 获得许可证的数量
     * @throws InterruptedException     当前线程是否中断
     * @throws IllegalArgumentException 如果 permits是否定的
     */
    public void acquire(int permits) throws InterruptedException {
        if (permits < 0) throw new IllegalArgumentException();
        sync.acquireSharedInterruptibly(permits);
    }

    /**
     * 从该信号量获取给定数量的许可证，阻止直到所有可用。
     * 获得一定数量的许可证，如果可用，并立即返回，将可用许可证数量减少给定数量。
     * 如果不足的许可证可用，那么当前线程将被禁用以进行线程调度，并且处于休眠状态，直到某个其他线程调用此信号量的一个release方法，当前线程将被分配许可证，并且可用许可证的数量满足此请求。
     * 如果当前线程在等待许可时为interrupted ，则它将继续等待，并且其在队列中的位置不受影响。 当该线程从该方法返回时，其中断状态将被设置。
     *
     * @param permits the number of permits to acquire
     * @throws IllegalArgumentException if {@code permits} is negative
     */
    public void acquireUninterruptibly(int permits) {
        if (permits < 0) throw new IllegalArgumentException();
        sync.acquireShared(permits);
    }

    /**
     * 从这个信号量获取给定数量的许可证，只有在调用时全部可用。
     * 获得给定数量的许可证（如果有），并立即返回，值为true ，将可用许可证数量减少给定金额。
     * 如果许可证不足，则该方法将立即返回值为false ，可用许可证数量不变。
     * 即使这个信号量被设置为使用公平的订购策略，如果一个可用的话，呼叫tryAcquire 将立即获得许可证，无论其他线程是否正在等待。
     * 这种“趸船”行为在某些情况下是有用的，尽管它打破了公平。 如果要尊重公平性，请使用tryAcquire(permits, 0, TimeUnit.SECONDS) ，这几乎相当（也检测到中断）。
     *
     * @param permits the number of permits to acquire
     * @return {@code true} if the permits were acquired and
     *         {@code false} otherwise
     * @throws IllegalArgumentException if {@code permits} is negative
     */
    public boolean tryAcquire(int permits) {
        if (permits < 0) throw new IllegalArgumentException();
        return sync.nonfairTryAcquireShared(permits) >= 0;
    }

    /**
     * @param permits the number of permits to acquire
     * @param timeout the maximum time to wait for the permits
     * @param unit the time unit of the {@code timeout} argument
     * @return {@code true} if all permits were acquired and {@code false}
     *         if the waiting time elapsed before all permits were acquired
     * @throws InterruptedException if the current thread is interrupted
     * @throws IllegalArgumentException if {@code permits} is negative
     */
    public boolean tryAcquire(int permits, long timeout, TimeUnit unit)
        throws InterruptedException {
        if (permits < 0) throw new IllegalArgumentException();
        return sync.tryAcquireSharedNanos(permits, unit.toNanos(timeout));
    }

    /**
     * @param permits the number of permits to release
     * @throws IllegalArgumentException if {@code permits} is negative
     */
    public void release(int permits) {
        if (permits < 0) throw new IllegalArgumentException();
        sync.releaseShared(permits);
    }

    /**
     * @return the number of permits available in this semaphore
     */
    public int availablePermits() {
        return sync.getPermits();
    }

    /**
     * @return the number of permits acquired
     */
    public int drainPermits() {
        return sync.drainPermits();
    }

    /**
     * @param reduction the number of permits to remove
     * @throws IllegalArgumentException if {@code reduction} is negative
     */
    protected void reducePermits(int reduction) {
        if (reduction < 0) throw new IllegalArgumentException();
        sync.reducePermits(reduction);
    }

    /**

     * @return {@code true} if this semaphore has fairness set true
     */
    public boolean isFair() {
        return sync instanceof FairSync;
    }

    /**
     * @return {@code true} if there may be other threads waiting to
     *         acquire the lock
     */
    public final boolean hasQueuedThreads() {
        return sync.hasQueuedThreads();
    }

    /**
     * @return the estimated number of threads waiting for this lock
     */
    public final int getQueueLength() {
        return sync.getQueueLength();
    }

    /**
     * @return the collection of threads
     */
    protected Collection<Thread> getQueuedThreads() {
        return sync.getQueuedThreads();
    }

    /**
     * @return a string identifying this semaphore, as well as its state
     */
    public String toString() {
        return super.toString() + "[Permits = " + sync.getPermits() + "]";
    }
}
